﻿using System.Threading.Tasks;
using Benchmark.Core.Communication.Data.Interface;
using Benchmark.Core.Communication.Data.Serialization;
using Benchmark.Core.Communication.Hub.Impl.Pipe.Core;
using Benchmark.Core.Communication.Model;

namespace Benchmark.Core.Communication.Hub.Impl.Pipe
{
    public class AsyncPipeServerEventArgument : PipeServer
    {
        readonly IFormatter _format;
        public AsyncPipeServerEventArgument() 
        {
           // _validate = validate;

            _format = new FormatterBinary();
        }

        public delegate void OnPreExecution();
        
        public delegate void OnPostExecution();

        public OnPreExecution OnPreExecutionDelegate { get; set; }

        public OnPostExecution OnPostExecutionDelegate { get; set; }


        public async Task<TPipeOutType> TestConnectionAsync<TPipeInType, TPipeOutType>(TPipeInType testBytes)
        {
            if (OnPreExecutionDelegate != null)
                OnPreExecutionDelegate();



            Task<TPipeOutType> message = await Task.Factory.StartNew<Task<TPipeOutType>>(async () =>
                  {


                      byte[] readBytes=_format.SerializeToByte<TPipeInType>(testBytes);
                      await base.WriteAsyn(readBytes);
                      readBytes = await base.ReadAsyn();
                      var decodedMessage = _format.DeserializeFromBytes<TPipeOutType>(readBytes);
                      return (decodedMessage);
                  }
              );
                if (OnPostExecutionDelegate != null)
                OnPostExecutionDelegate.Invoke();
            return (message.Result);
            

        }
        public async Task<bool> ConnectPipeAsync(string pipeName, string serverName)
        {

            byte[] readBytes=null;
            if (OnPreExecutionDelegate != null)
            { OnPreExecutionDelegate.Invoke(); }
            


            await Task.Factory.StartNew(() =>
                  {
                      base.Pipename = pipeName;
                      base.ServerName = serverName;
                                            base.Connect(1,true);
                      
                  });
             bool isconnected = base.Isconnected;

            OnPostExecutionDelegate.Invoke();
            return (isconnected);
        }
        public async Task<TPipeOutType> InitializeTestAsync<TPipeInType, TPipeOutType>(TPipeInType initiateModel)
        {

            if (OnPreExecutionDelegate != null)
                OnPreExecutionDelegate();


            Task<TPipeOutType> message = await Task.Factory.StartNew<Task<TPipeOutType>>( async() =>
               {
                   //WRITE THE INTIALIZE SEQUENCE
               byte[] modelInBytes = _format.SerializeToByte<string>(HubModel.OperationType.Initialize.ToString());
                  await base.WriteAsyn(modelInBytes);
                   //WRITE THE MODEL INITIATE
                  modelInBytes= _format.SerializeToByte<TPipeInType>(initiateModel);
                   await base.WriteAsyn(modelInBytes);
                   //READ THE STATUS SEQUENCE
                   modelInBytes = await base.ReadAsyn();
                   var decodedMessage = _format.DeserializeFromBytes<TPipeOutType>(modelInBytes);
                   //SEND BACK TO CALLER THE STRING TO CHECK IF ITS VALID
                   return (decodedMessage);
               }
                   );
            if (OnPostExecutionDelegate != null)
                OnPostExecutionDelegate.Invoke();
            return (message.Result);
        }



        public async Task<TPipeOutType> ExecuteTestAync<TPipeInType, TPipeOutType>(TPipeInType testBytes)
        {
            if (OnPreExecutionDelegate != null)
                OnPreExecutionDelegate();


            Task<TPipeOutType> message = await Task.Factory.StartNew<Task<TPipeOutType>>(async () =>
            {


                byte[] readBytes = _format.SerializeToByte<TPipeInType>(testBytes);
               await  base.WriteAsyn(readBytes);
                readBytes = await base.ReadAsyn();
                var decodedMessage = _format.DeserializeFromBytes<TPipeOutType>(readBytes);
                return (decodedMessage);
            }
              );
            if (OnPostExecutionDelegate != null)
                OnPostExecutionDelegate.Invoke();
            return (message.Result);


        }



        public async Task<TPipeOutType> FinishTestAsync<TPipeInType, TPipeOutType>(TPipeInType testBytes)
        {
            if (OnPreExecutionDelegate != null)
                OnPreExecutionDelegate();


            Task<TPipeOutType> message = await Task.Factory.StartNew<Task<TPipeOutType>>(async () =>
            {


                byte[] readBytes = _format.SerializeToByte<TPipeInType>(testBytes);
             await   base.WriteAsyn(readBytes);
                readBytes = await base.ReadAsyn();
                var decodedMessage = _format.DeserializeFromBytes<TPipeOutType>(readBytes);
                return (decodedMessage);
            }
              );
            if (OnPostExecutionDelegate != null)
                OnPostExecutionDelegate.Invoke();
            return (message.Result);


        }

        public async Task<TPipeOutType> ReleasePipeAsync<TPipeInType, TPipeOutType>(TPipeInType dataToWrite)
        {
            if (OnPreExecutionDelegate != null)
                OnPreExecutionDelegate();



            Task<TPipeOutType> message = await Task.Factory.StartNew<Task<TPipeOutType>>(async () =>
            {
                byte[] modelInBytes = _format.SerializeToByte<TPipeInType>(dataToWrite);
                await base.WriteAsyn(modelInBytes);
                //  Task<byte[]> result = base.ReadAsyn();
                modelInBytes = await base.ReadAsyn();
                var decodedMessage = _format.DeserializeFromBytes<TPipeOutType>(modelInBytes);

                return (decodedMessage);
            }
                );

            if (OnPostExecutionDelegate != null)
                OnPostExecutionDelegate.Invoke();
            return (message.Result);
        }



    }
}
